package com.hd.manager.shiro;

import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheException;
import org.apache.shiro.cache.CacheManager;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;

import java.util.Collection;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 * shiro redis缓存管理器
 * </p>
 *
 * @author Administrator
 * @since 2018-10-30
 */
public class ShiroRedisCacheManager implements CacheManager {

    private RedisTemplate redisTemplate;

    private long timeout = 60;//分钟为单位

    public ShiroRedisCacheManager(RedisTemplate redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    @Override
    public <K, V> Cache<K, V> getCache(String name) throws CacheException {
        return new ShiroRedisCache<>(name);
    }

    /**
     * 为 shiro 量身定做的一个 redis cache , 为 authorization cache 做了特别优化
     */
    public class ShiroRedisCache<K, V> implements Cache<K, V> {

        private String cacheKey;

        public ShiroRedisCache(String cacheKey) {
            this.cacheKey = cacheKey;
        }

        @Override
        public V get(K key) throws CacheException {
            Object k = hashKey(key);
            HashOperations<String, Object, V> operations = redisTemplate.opsForHash();
            V v = operations.get(cacheKey, k);
            return v;
        }

        @Override
        public V put(K key, V value) throws CacheException {
            Object k = hashKey(key);
            HashOperations<String, Object, V> operations = redisTemplate.opsForHash();
            operations.put(cacheKey, k, value);
            redisTemplate.expire(cacheKey, timeout, TimeUnit.MINUTES);
            return value;
        }

        @Override
        public V remove(K key) throws CacheException {
            Object k = hashKey(key);
            HashOperations<String, Object, V> operations = redisTemplate.opsForHash();
            V value = operations.get(cacheKey, k);
            operations.delete(cacheKey, k);
            return value;
        }

        @Override
        public void clear() throws CacheException {
            redisTemplate.delete(cacheKey);
        }

        @Override
        public int size() {
            return redisTemplate.opsForHash().size(cacheKey).intValue();
        }

        @Override
        public Set<K> keys() {
            HashOperations<String, K, V> operations = redisTemplate.opsForHash();
            return operations.keys(cacheKey);
        }

        @Override
        public Collection<V> values() {
            HashOperations<String, K, V> operations = redisTemplate.opsForHash();
            return operations.values(cacheKey);
        }

        protected Object hashKey(K key) {
            if (key instanceof PrincipalCollection) {
                //如果key是登录凭证,那么这是访问用户的授权缓存;
                //将登录凭证转为  用户  对象,返回 用户的id  做为 hash key,
                //否则会以 用户对象 做为 hash key, 这样就不好清除指定用户的缓存了
                PrincipalCollection pc = (PrincipalCollection) key;
                return "";
            }
            return key;
        }
    }

}
